/**************************************************************
*
* M3D_QUAT.H
*
* Dual quaternions support
**************************************************************/

class m3dQUAT_DUAL {
public:
   m3dQUAT
      q0,         // real part scaled by transformation scale 
      qe;         // dual part

public:
   m3dQUAT_DUAL         (void) {}
   m3dQUAT_DUAL         (const m3dQUAT *q0, const m3dQUAT *qe) : q0(*q0), qe(*qe) {}
   m3dQUAT_DUAL         (const m3dQUAT *rot, const m3dV *trans);

   m3dQUAT&       DualPart       (void)            { return qe; }
   const m3dQUAT& DualPart       (void) const      { return qe; }
   m3dQUAT&       RealPart       (void)            { return q0; }
   const m3dQUAT& RealPart       (void) const      { return q0; }

   // inversion of a dual quaternion with non-zero nondual part
   void           Inverse        (void);
   void           Inverse        (m3dQUAT_DUAL *dq) const { *dq = *this; dq->Inverse(); }

   void           Conjugate      (void);
   void           Conjugate      (m3dQUAT_DUAL *dq) const { *dq = *this; dq->Conjugate(); }

   void           Normalize      (void);
   void           Normalize      (m3dQUAT_DUAL *dq) const { *dq = *this; dq->Normalize(); }

   // normalization of the rotation component of dual quaternion (divide both nondual and dual part by magnitude of nondual part)
   void           RotationNormalize (void);
   void           RotationNormalize (m3dQUAT_DUAL *dq) const { *dq = *this; dq->RotationNormalize(); }

   // normalization of the translation component of dual quaternion (project dual part so that it satisfies Plucker's condition)	
   void           PluckerNormalize  (void);
   void           PluckerNormalize  (m3dQUAT_DUAL *dq) const { *dq = *this; dq->PluckerNormalize(); }

   void           Transform      (const m3dV *a, m3dV *res) const;
   void           Transform      (m3dV *vct) const    { Transform(vct, vct); }

   void           Identity       (void);
   void           SetZero        (void);

   // conversion from/to rigid transformation matrix
   float          FromRTMatrix   (const m3dMATR *matr);
   void           ToRTMatrix     (m3dMATR *matr) const;
   // non-dual and dual part of dot product (technical problem: dot product is a dual number)
   float          DotRealPart    (const m3dQUAT_DUAL *dq) const;
   float          DotDualPart    (const m3dQUAT_DUAL *dq) const;

   float          ExtractScale   (m3dQUAT_DUAL *res) const;
   void           StoreScale     (float scale);

   // DLB: linear blend (without normalization) of N dual quaternions with N convex weights
   static void DLB (int N, const float weight[], const m3dQUAT_DUAL q[], m3dQUAT_DUAL *res);
};

extern void    m3dAddQuatDual       (const m3dQUAT_DUAL *a, const m3dQUAT_DUAL *b, m3dQUAT_DUAL *res);   
extern void    m3dSubtractQuatDual  (const m3dQUAT_DUAL *a, const m3dQUAT_DUAL *b, m3dQUAT_DUAL *res);   
extern void    m3dScaleQuatDual     (const m3dQUAT_DUAL *a, float scale, m3dQUAT_DUAL *res);   
extern void    m3dMultiplyQuatDual  (const m3dQUAT_DUAL *a, const m3dQUAT_DUAL *b, m3dQUAT_DUAL *res);   
extern void    m3dLineCombine       (const m3dQUAT_DUAL *a, const m3dQUAT_DUAL *b, float kb, 
                                     m3dQUAT_DUAL *res);   
                                     
extern BOOL    m3dIsEqualQuatDual_A (const m3dQUAT_DUAL *a, const m3dQUAT_DUAL *b, float acc);   
inline BOOL    m3dIsEqualQuatDual   (const m3dQUAT_DUAL *a, const m3dQUAT_DUAL *b)    
{
   return m3dIsEqualQuatDual_A(a, b, M3D_EPSILON);
}

//
// End-of-file M3D_QUAT.H
//
